package factory;

import item.InteractiveItem;
import item.Item;
import item.Mount;
import item.NonWeapon;
import item.Obstacle;
import item.OneHanded;
import item.OneShotItem;
import item.Ranged;
import item.Staff;
import item.TakeableItem;
import item.Trap;
import item.TwoHanded;
import item.UsableItem;

import java.util.HashMap;
import java.util.Map;

import loadsave.Memento;
import loadsave.loadsaveobject.Iterator;
import loadsave.loadsaveobject.LoadSaveMapComposite;
import loadsave.loadsaveobject.LoadSaveObject;
import loadsave.loadsaveobject.LoadSaveObjectComposite;
import loadsave.loadsaveobject.LoadSavePrimitive;

public class ItemFactory implements loadsave.LoadSaveable {
    
    private static Map<String, Item> itemMap;
    private static Map<String, Trap> trapMap;
    private static Map<String, TakeableItem> takeableMap;
    
    /**
     * initialize the static maps
     */
    static {
        itemMap = new HashMap<String, Item>();
        trapMap = new HashMap<String, Trap>();
        takeableMap = new HashMap<String, TakeableItem>();
    }
    
    /**
     * return an Item based on the passed in LoadSaveObject
     * @param lso
     * @return
     */
    public static Item createItem( LoadSaveObject lso ) {
    	String name = lso.get("name").getValue();
    	if (itemMap.containsKey(name))
    		return itemMap.get(name);
    	Item item = createTrap(lso);
    	if (item != null)
    		return item;
    	return createTakeableItem(lso);
    }
    
    /**
     * return a Trap based on the LoadSaveObject
     * @param lso
     * @return
     */
    public static Trap createTrap( LoadSaveObject lso ) {
    	String name = lso.get("name").getValue();
    	return trapMap.get(name);
    }
    
    /**
     * return a TakeableItem from the LoadSaveObject
     * @param lso
     * @return
     */
    public static TakeableItem createTakeableItem (LoadSaveObject lso) {
    	String name = lso.get("name").getValue();
    	return takeableMap.get(name);
    }
    
    /**
     * add an Item to the map
     * @param item
     */
    public static void addItem( Item item ) {
        itemMap.put(item.getName(), item);
    }
    
    /**
     * ITS A TRAP
     * @param itsATrap
     */
    public static void addTrap(Trap itsATrap) {
    	trapMap.put(itsATrap.getName(), itsATrap);
    }

	@Override
	public Memento getMemento() {
		return new Memento() {
			
			@Override
			public LoadSaveObject getState() {
				LoadSaveObjectComposite toReturn = new LoadSaveObjectComposite("itemFactory", "ItemFactory");
				LoadSaveMapComposite lsmc = new LoadSaveMapComposite("itemMap", "HashMap", "String", "Item");
				for (String s : itemMap.keySet()) {
					lsmc.add(new LoadSavePrimitive("", "", s), itemMap.get(s).getMemento().getState());
				}
				toReturn.add(lsmc.getName(), lsmc);
				lsmc = new LoadSaveMapComposite("trapMap", "HashMap", "String", "Trap");
				for (String s : trapMap.keySet()) {
					lsmc.add(new LoadSavePrimitive("", "", s), trapMap.get(s).getMemento().getState());
				}
				toReturn.add(lsmc.getName(), lsmc);
				return toReturn;
			}

			@Override
			public void restoreState(LoadSaveObject lso) {
				Iterator<LoadSaveObject> iter = lso.get("itemMap").getIterator();
				Map<String, Item> itemTypes = new HashMap<String, Item>();
				//Wish we could've used reflection here
				itemTypes.put("InteractiveItem", new InteractiveItem());
				itemTypes.put("Mount", new Mount());
				itemTypes.put("NonWeapon", new NonWeapon());
				itemTypes.put("Obstacle", new Obstacle());
				itemTypes.put("OneHanded", new OneHanded());
				itemTypes.put("OneShotItem", new OneShotItem());
				itemTypes.put("Ranged", new Ranged());
				itemTypes.put("Staff", new Staff());
				itemTypes.put("Trap", new Trap());
				itemTypes.put("TwoHanded", new TwoHanded());
				itemTypes.put("UsableItem", new UsableItem());
				for (iter.init(); iter.hasNext(); iter.next()) {
					itemMap.put(iter.getCurrKey().getValue(), itemTypes.get(iter.getCurrVal().getType()).clone());
					itemMap.get(iter.getCurrKey().getValue()).getMemento().restoreState(iter.getCurrVal());
				}
			}
			
		};
	}

}
